package com.punch.oauth.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.google.code.kaptcha.Producer;
import com.punch.common.constant.SecurityConstants;
import com.punch.common.exception.BusinessException;
import com.punch.common.exception.CommonExceptionEnum;
import com.punch.common.feign.FeignUserService;
import com.punch.common.model.LoginUser;
import com.punch.common.model.Result;
import com.punch.common.simple.redis.utils.RedisUtil;
import com.punch.common.utils.AliSmsUtil;
import com.punch.common.utils.DateUtil;
import com.punch.common.utils.IpAddressUtil;
import com.punch.common.utils.PhoneUtils;
import com.punch.oauth.service.ValidateCodeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.time.LocalDateTime;

/**
 * ValidateCodeServiceImpl-
 *
 * @author wujj
 * @version 1.0.0
 * @since 2020/7/31 9:42
 */
@Service
@Slf4j
public class ValidateCodeServiceImpl implements ValidateCodeService {

    @Autowired
    private RedisUtil<String> redisUtil;

    @Resource
    private FeignUserService feignUserService;

    @Resource
    private TokenStore tokenStore;

    @Resource
    private Producer captchaProducer;


    /**
     * 发送验证码
     * <p>
     * 1. 先去redis 查询是否 60S内已经发送
     * 2. 未发送： 判断手机号是否存 ? false :产生4位数字  手机号-验证码
     * 3. 发往消息中心-》发送信息
     * 4. 保存redis
     *
     * @param mobile 手机号
     * @return true、false
     */
    @Override
    public Result<Boolean> sendSmsCode(String mobile, HttpServletRequest request) {
        if (!PhoneUtils.isPhone(mobile)) {
            return Result.failed("手机号码格式错误");
        }
        String tempCode = redisUtil.getValue(buildKey(mobile));
        if (StrUtil.isNotEmpty(tempCode)) {
            log.error("用户:{}验证码未失效{}", mobile, tempCode);
            return Result.failed("验证码未失效，请失效后再次申请");
        }
        //防止被多刷 ip现在
        String ip = IpAddressUtil.getIpAdrress(request);
        String ipLimitKey = SecurityConstants.IP_LIMIT_PRE_KEY + ip;
        String ipLimit = redisUtil.getValue(ipLimitKey);
        if (StrUtil.isEmpty(ipLimit)) {
            redisUtil.setValue(ipLimitKey, "1", DateUtil.getRemainSecondsOneDay(LocalDateTime.now()));
        } else {
            //同一个ip每天最多5次
            Integer limit = Integer.valueOf(ipLimit);
            if (limit > 5) {
                log.error("该ip每天五次超发:{}--手机号{}", ip, mobile);
               // return Result.failed("发生错误");
            }
            limit++;
            redisUtil.setValue(ipLimitKey, String.valueOf(limit), DateUtil.getRemainSecondsOneDay(LocalDateTime.now()));
        }
        String code = AliSmsUtil.getCode();
        log.info("短信发送请求消息中心 -> 手机号:{} -> 验证码：{}", mobile, code);
//        AliSmsUtil.sendSms(code, mobile);
        redisUtil.setValue(buildKey(mobile), code, SecurityConstants.DEFAULT_IMAGE_EXPIRE);
        return Result.succeed(true, "短信发送成功" + code);
    }

    /**
     * 微信验证token是否为空
     *
     * @param authorizationToken token
     * @return true/false
     */
    @Override
    public Result wxCheckToken(String authorizationToken) {
        String realToken = authorizationToken.replace("Bearer ", "");
        OAuth2AccessToken accessToken = tokenStore.readAccessToken(realToken);
        if (accessToken == null || accessToken.isExpired()) {
            return Result.succeed(false, "token过期");
        }
        return Result.succeed(true, "token未过期");
    }

    /**
     * 生成验证码
     *
     * @param request
     * @param response
     * @return string
     * @author wujj
     * @since 2020/6/5 18:35
     */
    @Override
    public void captchaCode(HttpServletRequest request, HttpServletResponse response) {
        String uuid = IdUtil.fastUUID();
        //禁止缓存
        response.setDateHeader("Expires", 0);
        response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
        response.addHeader("Cache-Control", "post-check=0, pre-check=0");
        response.setHeader("Pragma", "no-cache");
        //设置响应格式为png图片
        response.setContentType("image/png");
        response.setHeader("uuid", uuid);
        log.info("生成uuid:{}", uuid);
        //为验证码创建一个文本
        String codeText = captchaProducer.createText();
        //将验证码存到reids
        StringBuilder key = new StringBuilder();
        key.append("captcha:").append(uuid);
        redisUtil.setValue(key.toString(), codeText, 120L);
        // 用创建的验证码文本生成图片
        BufferedImage bi = captchaProducer.createImage(codeText);
        ServletOutputStream out = null;
        try {
            out = response.getOutputStream();
            //写出图片
            ImageIO.write(bi, "png", out);
            out.flush();
        } catch (IOException e) {
            log.info("生成图片IOException:{}", e.getMessage());
            throw new BusinessException(CommonExceptionEnum.SERVER_ERROR);
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                log.info("关闭IO流错误,IOException:{}", e.getMessage());
                throw new BusinessException(CommonExceptionEnum.SERVER_ERROR);
            }
        }
    }

    private String buildKey(String deviceId) {
        return SecurityConstants.DEFAULT_CODE_KEY + ":" + deviceId;
    }

}
